﻿using System;
using System.IO;
using System.Threading;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using YsTiffConverter.DataModel;
using SWF = System.Windows.Forms;

namespace YsTiffConverter.ViewModel
{
    /// <summary>
    /// Holds the save all frames window data.
    /// </summary>
    public class SaveAllFramesWindowViewModel
    {
        #region Events

        public event Action OnSaved;

        #endregion Events

        #region Fields

        private EditionCommand commandSave_;
        private EditionCommand commandBrowseFolder_;

        #endregion Fields

        #region Properties

        /// <summary>
        /// Gets or sets the SaveFramesData.
        /// </summary>
        public SaveFramesData SaveFramesData
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the command save.
        /// </summary>
        public ICommand CommandSave
        {
            get
            {
                if (commandSave_ == null)
                {
                    commandSave_ = new EditionCommand();
                    commandSave_.OnCanExecute += CommandSaveOnCanExecute;
                    commandSave_.OnExecute += CommandSaveOnExecute;
                }

                return commandSave_;
            }
        }

        /// <summary>
        /// Gets the command browse folder.
        /// </summary>
        public ICommand CommandBrowseFolder
        {
            get
            {
                if (commandBrowseFolder_ == null)
                {
                    commandBrowseFolder_ = new EditionCommand();
                    commandBrowseFolder_.OnCanExecute += CommandBrowseFolderOnCanExecute;
                    commandBrowseFolder_.OnExecute += CommandBrowseFolderOnExecute;
                }

                return commandBrowseFolder_;
            }
        }

        #endregion Properties

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the SaveAllFramesWindowViewModel class.
        /// </summary>
        /// <param name="fileName">The image file name.</param>
        public SaveAllFramesWindowViewModel(string fileName)
        {
            SaveFramesData = new SaveFramesData(fileName);
        }

        #endregion Constructors

        #region Methods

        /// <summary>
        /// Executes command save.
        /// </summary>
        /// <param name="parameter">Command parameter.</param>
        private void CommandSaveOnExecute(object parameter)
        {
            var thread = new Thread(SaveFrames);
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
        }

        /// <summary>
        /// Checks, if the command save may be executed.
        /// </summary>
        /// <param name="parameter">Command parameter.</param>
        /// <returns>True, if the command may be executed.</returns>
        private bool CommandSaveOnCanExecute(object parameter)
        {
            return SaveFramesData.ControlsAvailable;
        }

        /// <summary>
        /// Executes the command browse folder.
        /// </summary>
        /// <param name="parameter">The command parameter.</param>
        private void CommandBrowseFolderOnExecute(object parameter)
        {
            var folderBrowserDialog = new SWF.FolderBrowserDialog
            {
                SelectedPath = SaveFramesData.Folder,
                ShowNewFolderButton = true
            };

            if (folderBrowserDialog.ShowDialog() == SWF.DialogResult.OK)
            {
                SaveFramesData.Folder = folderBrowserDialog.SelectedPath;
            }
        }

        /// <summary>
        /// Checks, if the command browse folder may be executed.
        /// </summary>
        /// <param name="parameter">The command parameter.</param>
        /// <returns>True, if the command may be executed.</returns>
        private bool CommandBrowseFolderOnCanExecute(object parameter)
        {
            return SaveFramesData.ControlsAvailable;
        }

        /// <summary>
        /// Saves all frames.
        /// </summary>
        /// <param name="data">Data, not used.</param>
        private void SaveFrames(object data)
        {
            SaveFramesData.ControlsAvailable = false;
            SaveFramesData.ProgressBarVisibility = Visibility.Visible;
            
            if (OnSaved == null)
            {
                
            }
            var toClose = true;

            var tiffImage = new TiffImage();
            string error;
            if (!tiffImage.Open(SaveFramesData.SourceFileName, out error))
            {
                MessageBox.Show(error, "Save all frames JPEG", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            else
            {
                for (SaveFramesData.ImagePage = 1;
                   SaveFramesData.ImagePage <= tiffImage.FrameCount;
                   ++SaveFramesData.ImagePage)
                {
                    if (!SaveFrameAsJpeg(tiffImage[SaveFramesData.ImagePage - 1]))
                    {
                        toClose = false;
                        break;
                    }
                }    
            }

            SaveFramesData.ControlsAvailable = true;
            SaveFramesData.ProgressBarVisibility = Visibility.Hidden;

            if (toClose && OnSaved != null)
            {
                OnSaved();
            }
        }

        /// <summary>
        /// Saves one frame as JPEG file.
        /// </summary>
        /// <param name="frame">frame to save.</param>
        /// <returns>True, if succeeded.</returns>
        private bool SaveFrameAsJpeg(BitmapFrame frame)
        {
            var fileName = String.Format(@"{0}\{1}-Page-{2}.jpg",
                                         SaveFramesData.Folder, SaveFramesData.FileNamePrefix, SaveFramesData.ImagePage);
            
            SaveFramesData.FileName = Path.GetFileName(fileName);

            if (File.Exists(fileName))
            {
                var result =
                    MessageBox.Show(String.Format("The file \"{0}\" exists already. Do you want to rewrite the file?",
                                                  fileName),
                                    "Saving TIFF as JPEG", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
                switch (result)
                {
                    case MessageBoxResult.Cancel:
                        return false;
                    case MessageBoxResult.No:
                        return true;
                    case MessageBoxResult.Yes:
                        break;
                    default:
                        throw new Exception(String.Format("SaveFrameAsJpeg: unsupported result: {0}", result));
                }
            }

            using (var fileStream = new FileStream(fileName, FileMode.Create))
            {
                var encoder = new JpegBitmapEncoder
                {
                    QualityLevel = 100
                };
                encoder.Frames.Add(frame);
                encoder.Save(fileStream);
            }

            return true;
        }

        #endregion Methods
    }
}
